Returning to the example of substituting the pattern ‘sin(x)^2 + cos(x)^2’ with 1, we saw that the rule ‘opt(a) sin(x)^2 + opt(a) cos(x)^2 := a’ does a good job of finding suitable cases. Another solution would be to use the rule ‘cos(x)^2 := 1 - sin(x)^2’, followed by algebraic simplification if necessary. This rule will be the most effective way to do the job, but at the expense of making some changes that you might not desire.
Another algebraic rewrite rule is ‘exp(x+y) := exp(x) exp(y)’. To make this work with the j r command so that it can be easily targeted to a particular exponential in a large formula, you might wish to write the rule as ‘select(exp(x+y)) := select(exp(x) exp(y))’. The ‘select’ markers will be ignored by the regular a r command (see Selections with Rewrite Rules).
A surprisingly useful rewrite rule is ‘a/(b-c) := a*(b+c)/(b^2-c^2)’. This will simplify the formula whenever ‘b’ and/or ‘c’ can be made simpler by squaring. For example, applying this rule to ‘2 / (sqrt(2) + 3)’ yields ‘6:7 - 2:7 sqrt(2)’ (assuming Symbolic mode has been enabled to keep the square root from being evaluated to a floating-point approximation). This rule is also useful when working with symbolic complex numbers, e.g., ‘(a + b i) / (c + d i)’.
As another example, we could define our own “triangular
numbers” function with the rules ‘[tri(0) := 0, tri(n) := n + tri(n-1) ::
n>0]’. Enter this vector and store it in a
variable: s t trirules. Now, given a
suitable formula like ‘tri(5)’ on the stack, type
‘a r trirules’
to apply these rules repeatedly. After six applications, a
r will stop with 15 on the stack. Once these rules are
debugged, it would probably be most useful to add them to
EvalRules so that Calc will evaluate the new
tri function automatically. We could then use Z
K on the keyboard macro ' tri($) <RET> to
make a command that applies tri to the value on the
top of the stack. See Programming.
The following rule set, contributed
by
Francois Pinard, implements quaternions, a
generalization of the concept of complex numbers. Quaternions
have four components, and are here represented by function calls
‘quat(w,
[x,
y, z])’ with “real part”
w and the three “imaginary” parts
collected into a vector. Various arithmetical operations on
quaternions are supported. To use these rules, either add them to
EvalRules, or create a command based on a
r for simplifying quaternion formulas. A convenient way to
enter quaternions would be a command defined by a keyboard macro
containing: ' quat($$$$, [$$$, $$, $])
<RET>.
[ quat(w, x, y, z) := quat(w, [x, y, z]),
quat(w, [0, 0, 0]) := w,
abs(quat(w, v)) := hypot(w, v),
-quat(w, v) := quat(-w, -v),
r + quat(w, v) := quat(r + w, v) :: real(r),
r - quat(w, v) := quat(r - w, -v) :: real(r),
quat(w1, v1) + quat(w2, v2) := quat(w1 + w2, v1 + v2),
r * quat(w, v) := quat(r * w, r * v) :: real(r),
plain(quat(w1, v1) * quat(w2, v2))
:= quat(w1 * w2 - v1 * v2, w1 * v2 + w2 * v1 + cross(v1, v2)),
quat(w1, v1) / r := quat(w1 / r, v1 / r) :: real(r),
z / quat(w, v) := z * quatinv(quat(w, v)),
quatinv(quat(w, v)) := quat(w, -v) / (w^2 + v^2),
quatsqr(quat(w, v)) := quat(w^2 - v^2, 2 * w * v),
quat(w, v)^k := quatsqr(quat(w, v)^(k / 2))
:: integer(k) :: k > 0 :: k % 2 = 0,
quat(w, v)^k := quatsqr(quat(w, v)^((k - 1) / 2)) * quat(w, v)
:: integer(k) :: k > 2,
quat(w, v)^-k := quatinv(quat(w, v)^k) :: integer(k) :: k > 0 ]
Quaternions, like matrices, have non-commutative
multiplication. In other words, ‘q1 * q2 = q2 * q1’ is not necessarily
true if ‘q1’
and ‘q2’ are
quat forms. The ‘quat*quat’ rule above uses
plain to prevent Calc from rearranging the product.
It may also be wise to add the line ‘[quat(), matrix]’ to the
Decls matrix, to ensure that Calc's other algebraic
operations will not rearrange a quaternion product. See Declarations.
These rules also accept a four-argument quat
form, converting it to the preferred form in the first rule. If
you would rather see results in the four-argument form, just
append the two items ‘phase(2),
quat(w, [x, y, z]) := quat(w, x, y, z)’ to
the end of the rule set. (But remember that multi-phase rule sets
don't work in EvalRules.)